/*
* java
* Copyright (C) 2004
* 
* $Id: CL_tent.java,v 1.10 2005/02/20 21:50:52 salomo Exp $
*/
/*
Copyright (C) 1997-2001 Id Software, Inc.

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

*/
using System;
using Defines = Suake2.UI.Defines;
using Globals = Suake2.UI.Globals;
using player_state_t = Suake2.UI.game.player_state_t;
using Com = Suake2.UI.qcommon.Com;
using MSG = Suake2.UI.qcommon.MSG;
using model_t = Suake2.UI.render.model_t;
using S = Suake2.UI.sound.S;
using sfx_t = Suake2.UI.sound.sfx_t;
using Lib = Suake2.UI.util.Lib;
using Math3D = Suake2.UI.util.Math3D;
namespace Suake2.UI.client
{
	
	/// <summary> CL_tent</summary>
	public class CL_tent
	{
		private class AnonymousClassThinkAdapter:cl_sustain_t.ThinkAdapter
		{
			internal override void  think(cl_sustain_t self)
			{
				CL_newfx.ParticleSteamEffect2(self);
			}
		}
		private class AnonymousClassThinkAdapter1:cl_sustain_t.ThinkAdapter
		{
			internal override void  think(cl_sustain_t self)
			{
				CL_newfx.Widowbeamout(self);
			}
		}
		private class AnonymousClassThinkAdapter2:cl_sustain_t.ThinkAdapter
		{
			internal override void  think(cl_sustain_t self)
			{
				CL_newfx.Nukeblast(self);
			}
		}
		
		internal class explosion_t
		{
			internal int type;
			
			internal entity_t ent = new entity_t();
			
			internal int frames;
			
			internal float light;
			
			internal float[] lightcolor = new float[3];
			
			internal float start;
			
			internal int baseframe;
			
			internal virtual void  clear()
			{
				lightcolor[0] = lightcolor[1] = lightcolor[2] = light = start = type = frames = baseframe = 0;
				ent.clear();
			}
		}
		
		internal const int MAX_EXPLOSIONS = 32;
		
		internal static explosion_t[] cl_explosions = new explosion_t[MAX_EXPLOSIONS];
		
		internal const int MAX_BEAMS = 32;
		
		internal static beam_t[] cl_beams = new beam_t[MAX_BEAMS];
		
		//	  PMM - added this for player-linked beams. Currently only used by the
		// plasma beam
		internal static beam_t[] cl_playerbeams = new beam_t[MAX_BEAMS];
		
		internal const int MAX_LASERS = 32;
		
		internal static laser_t[] cl_lasers = new laser_t[MAX_LASERS];
		
		//	  ROGUE
		internal const int MAX_SUSTAINS = 32;
		
		internal static cl_sustain_t[] cl_sustains = new cl_sustain_t[MAX_SUSTAINS];
		
		internal class beam_t
		{
			internal int entity;
			
			internal int dest_entity;
			
			internal model_t model;
			
			internal int endtime;
			
			internal float[] offset = new float[3];
			
			internal float[] start = new float[3];
			
			internal float[] end = new float[3];
			
			internal virtual void  clear()
			{
				offset[0] = offset[1] = offset[2] = start[0] = start[1] = start[2] = end[0] = end[1] = end[2] = entity = dest_entity = endtime = 0;
				model = null;
			}
		}
		
		internal class laser_t
		{
			internal entity_t ent = new entity_t();
			
			internal int endtime;
			
			internal virtual void  clear()
			{
				endtime = 0;
				ent.clear();
			}
		}
		
		internal const int ex_free = 0;
		
		internal const int ex_explosion = 1;
		
		internal const int ex_misc = 2;
		
		internal const int ex_flash = 3;
		
		internal const int ex_mflash = 4;
		
		internal const int ex_poly = 5;
		
		internal const int ex_poly2 = 6;
		
		//	  ROGUE
		
		// all are references;
		internal static sfx_t cl_sfx_ric1;
		
		internal static sfx_t cl_sfx_ric2;
		
		internal static sfx_t cl_sfx_ric3;
		
		internal static sfx_t cl_sfx_lashit;
		
		internal static sfx_t cl_sfx_spark5;
		
		internal static sfx_t cl_sfx_spark6;
		
		internal static sfx_t cl_sfx_spark7;
		
		internal static sfx_t cl_sfx_railg;
		
		internal static sfx_t cl_sfx_rockexp;
		
		internal static sfx_t cl_sfx_grenexp;
		
		internal static sfx_t cl_sfx_watrexp;
		
		// RAFAEL
		internal static sfx_t cl_sfx_plasexp;
		
		internal static sfx_t[] cl_sfx_footsteps = new sfx_t[4];
		
		internal static model_t cl_mod_explode;
		
		internal static model_t cl_mod_smoke;
		
		internal static model_t cl_mod_flash;
		
		internal static model_t cl_mod_parasite_segment;
		
		internal static model_t cl_mod_grapple_cable;
		
		internal static model_t cl_mod_parasite_tip;
		
		internal static model_t cl_mod_explo4;
		
		internal static model_t cl_mod_bfg_explo;
		
		internal static model_t cl_mod_powerscreen;
		
		//	   RAFAEL
		internal static model_t cl_mod_plasmaexplo;
		
		//	  ROGUE
		internal static sfx_t cl_sfx_lightning;
		
		internal static sfx_t cl_sfx_disrexp;
		
		internal static model_t cl_mod_lightning;
		
		internal static model_t cl_mod_heatbeam;
		
		internal static model_t cl_mod_monster_heatbeam;
		
		internal static model_t cl_mod_explo4_big;
		
		//	  ROGUE
		/*
		* ================= CL_RegisterTEntSounds =================
		*/
		internal static void  RegisterTEntSounds()
		{
			int i;
			System.String name;
			
			// PMM - version stuff
			//		Com_Printf ("%s\n", ROGUE_VERSION_STRING);
			// PMM
			cl_sfx_ric1 = S.RegisterSound("world/ric1.wav");
			cl_sfx_ric2 = S.RegisterSound("world/ric2.wav");
			cl_sfx_ric3 = S.RegisterSound("world/ric3.wav");
			cl_sfx_lashit = S.RegisterSound("weapons/lashit.wav");
			cl_sfx_spark5 = S.RegisterSound("world/spark5.wav");
			cl_sfx_spark6 = S.RegisterSound("world/spark6.wav");
			cl_sfx_spark7 = S.RegisterSound("world/spark7.wav");
			cl_sfx_railg = S.RegisterSound("weapons/railgf1a.wav");
			cl_sfx_rockexp = S.RegisterSound("weapons/rocklx1a.wav");
			cl_sfx_grenexp = S.RegisterSound("weapons/grenlx1a.wav");
			cl_sfx_watrexp = S.RegisterSound("weapons/xpld_wat.wav");
			// RAFAEL
			// cl_sfx_plasexp = S.RegisterSound ("weapons/plasexpl.wav");
			S.RegisterSound("player/land1.wav");
			
			S.RegisterSound("player/fall2.wav");
			S.RegisterSound("player/fall1.wav");
			
			for (i = 0; i < 4; i++)
			{
				//Com_sprintf (name, sizeof(name), "player/step%i.wav", i+1);
				name = "player/step" + (i + 1) + ".wav";
				cl_sfx_footsteps[i] = S.RegisterSound(name);
			}
			
			//	  PGM
			cl_sfx_lightning = S.RegisterSound("weapons/tesla.wav");
			cl_sfx_disrexp = S.RegisterSound("weapons/disrupthit.wav");
			// version stuff
			//		sprintf (name, "weapons/sound%d.wav", ROGUE_VERSION_ID);
			//		if (name[0] == 'w')
			//			name[0] = 'W';
			//	  PGM
		}
		
		/*
		* ================= CL_RegisterTEntModels =================
		*/
		internal static void  RegisterTEntModels()
		{
			cl_mod_explode = Globals.re.RegisterModel("models/objects/explode/tris.md2");
			cl_mod_smoke = Globals.re.RegisterModel("models/objects/smoke/tris.md2");
			cl_mod_flash = Globals.re.RegisterModel("models/objects/flash/tris.md2");
			cl_mod_parasite_segment = Globals.re.RegisterModel("models/monsters/parasite/segment/tris.md2");
			cl_mod_grapple_cable = Globals.re.RegisterModel("models/ctf/segment/tris.md2");
			cl_mod_parasite_tip = Globals.re.RegisterModel("models/monsters/parasite/tip/tris.md2");
			cl_mod_explo4 = Globals.re.RegisterModel("models/objects/r_explode/tris.md2");
			cl_mod_bfg_explo = Globals.re.RegisterModel("sprites/s_bfg2.sp2");
			cl_mod_powerscreen = Globals.re.RegisterModel("models/items/armor/effect/tris.md2");
			
			Globals.re.RegisterModel("models/objects/laser/tris.md2");
			Globals.re.RegisterModel("models/objects/grenade2/tris.md2");
			Globals.re.RegisterModel("models/weapons/v_machn/tris.md2");
			Globals.re.RegisterModel("models/weapons/v_handgr/tris.md2");
			Globals.re.RegisterModel("models/weapons/v_shotg2/tris.md2");
			Globals.re.RegisterModel("models/objects/gibs/bone/tris.md2");
			Globals.re.RegisterModel("models/objects/gibs/sm_meat/tris.md2");
			Globals.re.RegisterModel("models/objects/gibs/bone2/tris.md2");
			//	   RAFAEL
			//	   re.RegisterModel ("models/objects/blaser/tris.md2");
			
			Globals.re.RegisterPic("w_machinegun");
			Globals.re.RegisterPic("a_bullets");
			Globals.re.RegisterPic("i_health");
			Globals.re.RegisterPic("a_grenades");
			
			//	  ROGUE
			cl_mod_explo4_big = Globals.re.RegisterModel("models/objects/r_explode2/tris.md2");
			cl_mod_lightning = Globals.re.RegisterModel("models/proj/lightning/tris.md2");
			cl_mod_heatbeam = Globals.re.RegisterModel("models/proj/beam/tris.md2");
			cl_mod_monster_heatbeam = Globals.re.RegisterModel("models/proj/widowbeam/tris.md2");
			//	  ROGUE
		}
		
		/*
		* ================= CL_ClearTEnts =================
		*/
		internal static void  ClearTEnts()
		{
			//		memset (cl_beams, 0, sizeof(cl_beams));
			for (int i = 0; i < cl_beams.Length; i++)
				cl_beams[i].clear();
			//		memset (cl_explosions, 0, sizeof(cl_explosions));
			for (int i = 0; i < cl_explosions.Length; i++)
				cl_explosions[i].clear();
			//		memset (cl_lasers, 0, sizeof(cl_lasers));
			for (int i = 0; i < cl_lasers.Length; i++)
				cl_lasers[i].clear();
			//
			//	  ROGUE
			//		memset (cl_playerbeams, 0, sizeof(cl_playerbeams));
			for (int i = 0; i < cl_playerbeams.Length; i++)
				cl_playerbeams[i].clear();
			//		memset (cl_sustains, 0, sizeof(cl_sustains));
			for (int i = 0; i < cl_sustains.Length; i++)
				cl_sustains[i].clear();
			//	  ROGUE
		}
		
		/*
		* ================= CL_AllocExplosion =================
		*/
		internal static explosion_t AllocExplosion()
		{
			int i;
			int time;
			int index;
			
			for (i = 0; i < MAX_EXPLOSIONS; i++)
			{
				if (cl_explosions[i].type == ex_free)
				{
					//memset (&cl_explosions[i], 0, sizeof (cl_explosions[i]));
					cl_explosions[i].clear();
					return cl_explosions[i];
				}
			}
			//	   find the oldest explosion
			time = Globals.cl.time;
			index = 0;
			
			for (i = 0; i < MAX_EXPLOSIONS; i++)
				if (cl_explosions[i].start < time)
				{
					//UPGRADE_WARNING: Data types in Visual C# might be different.  Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'"
					time = (int) cl_explosions[i].start;
					index = i;
				}
			//memset (&cl_explosions[index], 0, sizeof (cl_explosions[index]));
			cl_explosions[index].clear();
			return cl_explosions[index];
		}
		
		/*
		* ================= CL_SmokeAndFlash =================
		*/
		internal static void  SmokeAndFlash(float[] origin)
		{
			explosion_t ex;
			
			ex = AllocExplosion();
			Math3D.VectorCopy(origin, ex.ent.origin);
			ex.type = ex_misc;
			ex.frames = 4;
			ex.ent.flags = Defines.RF_TRANSLUCENT;
			ex.start = Globals.cl.frame.servertime - 100;
			ex.ent.model = cl_mod_smoke;
			
			ex = AllocExplosion();
			Math3D.VectorCopy(origin, ex.ent.origin);
			ex.type = ex_flash;
			ex.ent.flags = Defines.RF_FULLBRIGHT;
			ex.frames = 2;
			ex.start = Globals.cl.frame.servertime - 100;
			ex.ent.model = cl_mod_flash;
		}
		
		/*
		* =================
		* CL_ParseBeam
		* =================
		*/
		internal static int ParseBeam(model_t model)
		{
			int ent;
			float[] start = new float[3];
			float[] end = new float[3];
			beam_t[] b;
			int i;
			
			ent = MSG.ReadShort(Globals.net_message);
			
			MSG.ReadPos(Globals.net_message, start);
			MSG.ReadPos(Globals.net_message, end);
			
			//	   override any beam with the same entity
			b = cl_beams;
			for (i = 0; i < MAX_BEAMS; i++)
				if (b[i].entity == ent)
				{
					b[i].entity = ent;
					b[i].model = model;
					b[i].endtime = Globals.cl.time + 200;
					Math3D.VectorCopy(start, b[i].start);
					Math3D.VectorCopy(end, b[i].end);
					Math3D.VectorClear(b[i].offset);
					return ent;
				}
			
			//	   find a free beam
			b = cl_beams;
			for (i = 0; i < MAX_BEAMS; i++)
			{
				if (b[i].model == null || b[i].endtime < Globals.cl.time)
				{
					b[i].entity = ent;
					b[i].model = model;
					b[i].endtime = Globals.cl.time + 200;
					Math3D.VectorCopy(start, b[i].start);
					Math3D.VectorCopy(end, b[i].end);
					Math3D.VectorClear(b[i].offset);
					return ent;
				}
			}
			Com.Printf("beam list overflow!\n");
			return ent;
		}
		
		/*
		* ================= CL_ParseBeam2 =================
		*/
		internal static int ParseBeam2(model_t model)
		{
			int ent;
			float[] start = new float[3];
			float[] end = new float[3];
			float[] offset = new float[3];
			beam_t[] b;
			int i;
			
			ent = MSG.ReadShort(Globals.net_message);
			
			MSG.ReadPos(Globals.net_message, start);
			MSG.ReadPos(Globals.net_message, end);
			MSG.ReadPos(Globals.net_message, offset);
			
			//		Com_Printf ("end- %f %f %f\n", end[0], end[1], end[2]);
			
			//	   override any beam with the same entity
			b = cl_beams;
			for (i = 0; i < MAX_BEAMS; i++)
				if (b[i].entity == ent)
				{
					b[i].entity = ent;
					b[i].model = model;
					b[i].endtime = Globals.cl.time + 200;
					Math3D.VectorCopy(start, b[i].start);
					Math3D.VectorCopy(end, b[i].end);
					Math3D.VectorCopy(offset, b[i].offset);
					return ent;
				}
			
			//	   find a free beam
			b = cl_beams;
			for (i = 0; i < MAX_BEAMS; i++)
			{
				if (b[i].model == null || b[i].endtime < Globals.cl.time)
				{
					b[i].entity = ent;
					b[i].model = model;
					b[i].endtime = Globals.cl.time + 200;
					Math3D.VectorCopy(start, b[i].start);
					Math3D.VectorCopy(end, b[i].end);
					Math3D.VectorCopy(offset, b[i].offset);
					return ent;
				}
			}
			Com.Printf("beam list overflow!\n");
			return ent;
		}
		
		//	   ROGUE
		/*
		* ================= CL_ParsePlayerBeam - adds to the cl_playerbeam array
		* instead of the cl_beams array =================
		*/
		internal static int ParsePlayerBeam(model_t model)
		{
			int ent;
			float[] start = new float[3];
			float[] end = new float[3];
			float[] offset = new float[3];
			beam_t[] b;
			int i;
			
			ent = MSG.ReadShort(Globals.net_message);
			
			MSG.ReadPos(Globals.net_message, start);
			MSG.ReadPos(Globals.net_message, end);
			// PMM - network optimization
			if (model == cl_mod_heatbeam)
				Math3D.VectorSet(offset, 2, 7, - 3);
			else if (model == cl_mod_monster_heatbeam)
			{
				model = cl_mod_heatbeam;
				Math3D.VectorSet(offset, 0, 0, 0);
			}
			else
				MSG.ReadPos(Globals.net_message, offset);
			
			//		Com_Printf ("end- %f %f %f\n", end[0], end[1], end[2]);
			
			//	   override any beam with the same entity
			//	   PMM - For player beams, we only want one per player (entity) so..
			b = cl_playerbeams;
			for (i = 0; i < MAX_BEAMS; i++)
			{
				if (b[i].entity == ent)
				{
					b[i].entity = ent;
					b[i].model = model;
					b[i].endtime = Globals.cl.time + 200;
					Math3D.VectorCopy(start, b[i].start);
					Math3D.VectorCopy(end, b[i].end);
					Math3D.VectorCopy(offset, b[i].offset);
					return ent;
				}
			}
			
			//	   find a free beam
			b = cl_playerbeams;
			for (i = 0; i < MAX_BEAMS; i++)
			{
				if (b[i].model == null || b[i].endtime < Globals.cl.time)
				{
					b[i].entity = ent;
					b[i].model = model;
					b[i].endtime = Globals.cl.time + 100; // PMM - this needs to be
					// 100 to prevent multiple
					// heatbeams
					Math3D.VectorCopy(start, b[i].start);
					Math3D.VectorCopy(end, b[i].end);
					Math3D.VectorCopy(offset, b[i].offset);
					return ent;
				}
			}
			Com.Printf("beam list overflow!\n");
			return ent;
		}
		
		//	  rogue
		
		// stack variable
		//UPGRADE_NOTE: Final was removed from the declaration of 'start '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
		private static readonly float[] start = new float[3];
		//UPGRADE_NOTE: Final was removed from the declaration of 'end '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
		private static readonly float[] end = new float[3];
		/*
		* ================= CL_ParseLightning =================
		*/
		internal static int ParseLightning(model_t model)
		{
			int srcEnt, destEnt;
			beam_t[] b;
			int i;
			
			srcEnt = MSG.ReadShort(Globals.net_message);
			destEnt = MSG.ReadShort(Globals.net_message);
			
			MSG.ReadPos(Globals.net_message, start);
			MSG.ReadPos(Globals.net_message, end);
			
			//	   override any beam with the same source AND destination entities
			b = cl_beams;
			for (i = 0; i < MAX_BEAMS; i++)
				if (b[i].entity == srcEnt && b[i].dest_entity == destEnt)
				{
					//				Com_Printf("%d: OVERRIDE %d . %d\n", cl.time, srcEnt,
					// destEnt);
					b[i].entity = srcEnt;
					b[i].dest_entity = destEnt;
					b[i].model = model;
					b[i].endtime = Globals.cl.time + 200;
					Math3D.VectorCopy(start, b[i].start);
					Math3D.VectorCopy(end, b[i].end);
					Math3D.VectorClear(b[i].offset);
					return srcEnt;
				}
			
			//	   find a free beam
			b = cl_beams;
			for (i = 0; i < MAX_BEAMS; i++)
			{
				if (b[i].model == null || b[i].endtime < Globals.cl.time)
				{
					//				Com_Printf("%d: NORMAL %d . %d\n", cl.time, srcEnt, destEnt);
					b[i].entity = srcEnt;
					b[i].dest_entity = destEnt;
					b[i].model = model;
					b[i].endtime = Globals.cl.time + 200;
					Math3D.VectorCopy(start, b[i].start);
					Math3D.VectorCopy(end, b[i].end);
					Math3D.VectorClear(b[i].offset);
					return srcEnt;
				}
			}
			Com.Printf("beam list overflow!\n");
			return srcEnt;
		}
		
		// stack variable
		// start, end
		/*
		* ================= CL_ParseLaser =================
		*/
		internal static void  ParseLaser(int colors)
		{
			laser_t[] l;
			int i;
			
			MSG.ReadPos(Globals.net_message, start);
			MSG.ReadPos(Globals.net_message, end);
			
			l = cl_lasers;
			for (i = 0; i < MAX_LASERS; i++)
			{
				if (l[i].endtime < Globals.cl.time)
				{
					l[i].ent.flags = Defines.RF_TRANSLUCENT | Defines.RF_BEAM;
					Math3D.VectorCopy(start, l[i].ent.origin);
					Math3D.VectorCopy(end, l[i].ent.oldorigin);
					l[i].ent.alpha = 0.30f;
					l[i].ent.skinnum = (colors >> ((Lib.rand() % 4) * 8)) & 0xff;
					l[i].ent.model = null;
					l[i].ent.frame = 4;
					l[i].endtime = Globals.cl.time + 100;
					return ;
				}
			}
		}
		
		// stack variable
		//UPGRADE_NOTE: Final was removed from the declaration of 'pos '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
		private static readonly float[] pos = new float[3];
		//UPGRADE_NOTE: Final was removed from the declaration of 'dir '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
		private static readonly float[] dir = new float[3];
		//	  =============
		//	  ROGUE
		internal static void  ParseSteam()
		{
			int id, i;
			int r;
			int cnt;
			int color;
			int magnitude;
			cl_sustain_t[] s;
			cl_sustain_t free_sustain;
			
			id = MSG.ReadShort(Globals.net_message); // an id of -1 is an instant
			// effect
			if (id != - 1)
			// sustains
			{
				//				Com_Printf ("Sustain effect id %d\n", id);
				free_sustain = null;
				s = cl_sustains;
				for (i = 0; i < MAX_SUSTAINS; i++)
				{
					if (s[i].id == 0)
					{
						free_sustain = s[i];
						break;
					}
				}
				if (free_sustain != null)
				{
					s[i].id = id;
					s[i].count = MSG.ReadByte(Globals.net_message);
					MSG.ReadPos(Globals.net_message, s[i].org);
					MSG.ReadDir(Globals.net_message, s[i].dir);
					r = MSG.ReadByte(Globals.net_message);
					s[i].color = r & 0xff;
					s[i].magnitude = MSG.ReadShort(Globals.net_message);
					s[i].endtime = Globals.cl.time + MSG.ReadLong(Globals.net_message);
					s[i].think = new AnonymousClassThinkAdapter();
					s[i].thinkinterval = 100;
					s[i].nextthink = Globals.cl.time;
				}
				else
				{
					//					Com_Printf ("No free sustains!\n");
					// FIXME - read the stuff anyway
					cnt = MSG.ReadByte(Globals.net_message);
					MSG.ReadPos(Globals.net_message, pos);
					MSG.ReadDir(Globals.net_message, dir);
					r = MSG.ReadByte(Globals.net_message);
					magnitude = MSG.ReadShort(Globals.net_message);
					magnitude = MSG.ReadLong(Globals.net_message); // really
					// interval
				}
			}
			// instant
			else
			{
				cnt = MSG.ReadByte(Globals.net_message);
				MSG.ReadPos(Globals.net_message, pos);
				MSG.ReadDir(Globals.net_message, dir);
				r = MSG.ReadByte(Globals.net_message);
				magnitude = MSG.ReadShort(Globals.net_message);
				color = r & 0xff;
				CL_newfx.ParticleSteamEffect(pos, dir, color, cnt, magnitude);
				//			S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
			}
		}
		
		// stack variable
		// pos
		internal static void  ParseWidow()
		{
			int id, i;
			cl_sustain_t[] s;
			cl_sustain_t free_sustain;
			
			id = MSG.ReadShort(Globals.net_message);
			
			free_sustain = null;
			s = cl_sustains;
			for (i = 0; i < MAX_SUSTAINS; i++)
			{
				if (s[i].id == 0)
				{
					free_sustain = s[i];
					break;
				}
			}
			if (free_sustain != null)
			{
				s[i].id = id;
				MSG.ReadPos(Globals.net_message, s[i].org);
				s[i].endtime = Globals.cl.time + 2100;
				s[i].think = new AnonymousClassThinkAdapter1();
				s[i].thinkinterval = 1;
				s[i].nextthink = Globals.cl.time;
			}
			// no free sustains
			else
			{
				// FIXME - read the stuff anyway
				MSG.ReadPos(Globals.net_message, pos);
			}
		}
		
		// stack variable
		// pos
		internal static void  ParseNuke()
		{
			int i;
			cl_sustain_t[] s;
			cl_sustain_t free_sustain;
			
			free_sustain = null;
			s = cl_sustains;
			for (i = 0; i < MAX_SUSTAINS; i++)
			{
				if (s[i].id == 0)
				{
					free_sustain = s[i];
					break;
				}
			}
			if (free_sustain != null)
			{
				s[i].id = 21000;
				MSG.ReadPos(Globals.net_message, s[i].org);
				s[i].endtime = Globals.cl.time + 1000;
				s[i].think = new AnonymousClassThinkAdapter2();
				s[i].thinkinterval = 1;
				s[i].nextthink = Globals.cl.time;
			}
			// no free sustains
			else
			{
				// FIXME - read the stuff anyway
				MSG.ReadPos(Globals.net_message, pos);
			}
		}
		
		//	  ROGUE
		//	  =============
		
		/*
		* ================= CL_ParseTEnt =================
		*/
		internal static int[] splash_color = new int[]{0x00, 0xe0, 0xb0, 0x50, 0xd0, 0xe0, 0xe8};
		// stack variable
		// pos, dir
		//UPGRADE_NOTE: Final was removed from the declaration of 'pos2'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
		private static readonly float[] pos2 = new float[]{0, 0, 0};
		
		internal static void  ParseTEnt()
		{
			int type;
			explosion_t ex;
			int cnt;
			int color;
			int r;
			int ent;
			int magnitude;
			
			type = MSG.ReadByte(Globals.net_message);
			
			switch (type)
			{
				
				case Defines.TE_BLOOD:  // bullet hitting flesh
					MSG.ReadPos(Globals.net_message, pos);
					MSG.ReadDir(Globals.net_message, dir);
					CL_fx.ParticleEffect(pos, dir, 0xe8, 60);
					break;
				
				
				case Defines.TE_GUNSHOT: 
				// bullet hitting wall
				case Defines.TE_SPARKS: 
				case Defines.TE_BULLET_SPARKS: 
					MSG.ReadPos(Globals.net_message, pos);
					MSG.ReadDir(Globals.net_message, dir);
					if (type == Defines.TE_GUNSHOT)
						CL_fx.ParticleEffect(pos, dir, 0, 40);
					else
						CL_fx.ParticleEffect(pos, dir, 0xe0, 6);
					
					if (type != Defines.TE_SPARKS)
					{
						SmokeAndFlash(pos);
						
						// impact sound
						cnt = Lib.rand() & 15;
						if (cnt == 1)
							S.StartSound(pos, 0, 0, cl_sfx_ric1, 1, Defines.ATTN_NORM, 0);
						else if (cnt == 2)
							S.StartSound(pos, 0, 0, cl_sfx_ric2, 1, Defines.ATTN_NORM, 0);
						else if (cnt == 3)
							S.StartSound(pos, 0, 0, cl_sfx_ric3, 1, Defines.ATTN_NORM, 0);
					}
					
					break;
				
				
				case Defines.TE_SCREEN_SPARKS: 
				case Defines.TE_SHIELD_SPARKS: 
					MSG.ReadPos(Globals.net_message, pos);
					MSG.ReadDir(Globals.net_message, dir);
					if (type == Defines.TE_SCREEN_SPARKS)
						CL_fx.ParticleEffect(pos, dir, 0xd0, 40);
					else
						CL_fx.ParticleEffect(pos, dir, 0xb0, 40);
					//FIXME : replace or remove this sound
					S.StartSound(pos, 0, 0, cl_sfx_lashit, 1, Defines.ATTN_NORM, 0);
					break;
				
				
				case Defines.TE_SHOTGUN:  // bullet hitting wall
					MSG.ReadPos(Globals.net_message, pos);
					MSG.ReadDir(Globals.net_message, dir);
					CL_fx.ParticleEffect(pos, dir, 0, 20);
					SmokeAndFlash(pos);
					break;
				
				
				case Defines.TE_SPLASH:  // bullet hitting water
					cnt = MSG.ReadByte(Globals.net_message);
					MSG.ReadPos(Globals.net_message, pos);
					MSG.ReadDir(Globals.net_message, dir);
					r = MSG.ReadByte(Globals.net_message);
					if (r > 6)
						color = 0x00;
					else
						color = splash_color[r];
					CL_fx.ParticleEffect(pos, dir, color, cnt);
					
					if (r == Defines.SPLASH_SPARKS)
					{
						r = Lib.rand() & 3;
						if (r == 0)
							S.StartSound(pos, 0, 0, cl_sfx_spark5, 1, Defines.ATTN_STATIC, 0);
						else if (r == 1)
							S.StartSound(pos, 0, 0, cl_sfx_spark6, 1, Defines.ATTN_STATIC, 0);
						else
							S.StartSound(pos, 0, 0, cl_sfx_spark7, 1, Defines.ATTN_STATIC, 0);
					}
					break;
				
				
				case Defines.TE_LASER_SPARKS: 
					cnt = MSG.ReadByte(Globals.net_message);
					MSG.ReadPos(Globals.net_message, pos);
					MSG.ReadDir(Globals.net_message, dir);
					color = MSG.ReadByte(Globals.net_message);
					CL_fx.ParticleEffect2(pos, dir, color, cnt);
					break;
					
					// RAFAEL
				
				case Defines.TE_BLUEHYPERBLASTER: 
					MSG.ReadPos(Globals.net_message, pos);
					MSG.ReadPos(Globals.net_message, dir);
					CL_fx.BlasterParticles(pos, dir);
					break;
				
				
				case Defines.TE_BLASTER:  // blaster hitting wall
					MSG.ReadPos(Globals.net_message, pos);
					MSG.ReadDir(Globals.net_message, dir);
					CL_fx.BlasterParticles(pos, dir);
					
					ex = AllocExplosion();
					Math3D.VectorCopy(pos, ex.ent.origin);
					//UPGRADE_WARNING: Data types in Visual C# might be different.  Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'"
					ex.ent.angles[0] = (float) (System.Math.Acos(dir[2]) / System.Math.PI * 180);
					// PMM - fixed to correct for pitch of 0
					if (dir[0] != 0.0f)
					{
						//UPGRADE_WARNING: Data types in Visual C# might be different.  Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'"
						ex.ent.angles[1] = (float) (System.Math.Atan2(dir[1], dir[0]) / System.Math.PI * 180);
					}
					else if (dir[1] > 0)
						ex.ent.angles[1] = 90;
					else if (dir[1] < 0)
						ex.ent.angles[1] = 270;
					else
						ex.ent.angles[1] = 0;
					
					ex.type = ex_misc;
					ex.ent.flags = Defines.RF_FULLBRIGHT | Defines.RF_TRANSLUCENT;
					ex.start = Globals.cl.frame.servertime - 100;
					ex.light = 150;
					ex.lightcolor[0] = 1;
					ex.lightcolor[1] = 1;
					ex.ent.model = cl_mod_explode;
					ex.frames = 4;
					S.StartSound(pos, 0, 0, cl_sfx_lashit, 1, Defines.ATTN_NORM, 0);
					break;
				
				
				case Defines.TE_RAILTRAIL:  // railgun effect
					MSG.ReadPos(Globals.net_message, pos);
					MSG.ReadPos(Globals.net_message, pos2);
					CL_fx.RailTrail(pos, pos2);
					S.StartSound(pos2, 0, 0, cl_sfx_railg, 1, Defines.ATTN_NORM, 0);
					break;
				
				
				case Defines.TE_EXPLOSION2: 
				case Defines.TE_GRENADE_EXPLOSION: 
				case Defines.TE_GRENADE_EXPLOSION_WATER: 
					MSG.ReadPos(Globals.net_message, pos);
					
					ex = AllocExplosion();
					Math3D.VectorCopy(pos, ex.ent.origin);
					ex.type = ex_poly;
					ex.ent.flags = Defines.RF_FULLBRIGHT;
					ex.start = Globals.cl.frame.servertime - 100;
					ex.light = 350;
					ex.lightcolor[0] = 1.0f;
					ex.lightcolor[1] = 0.5f;
					ex.lightcolor[2] = 0.5f;
					ex.ent.model = cl_mod_explo4;
					ex.frames = 19;
					ex.baseframe = 30;
					ex.ent.angles[1] = Lib.rand() % 360;
					CL_fx.ExplosionParticles(pos);
					if (type == Defines.TE_GRENADE_EXPLOSION_WATER)
						S.StartSound(pos, 0, 0, cl_sfx_watrexp, 1, Defines.ATTN_NORM, 0);
					else
						S.StartSound(pos, 0, 0, cl_sfx_grenexp, 1, Defines.ATTN_NORM, 0);
					break;
					
					// RAFAEL
				
				case Defines.TE_PLASMA_EXPLOSION: 
					MSG.ReadPos(Globals.net_message, pos);
					ex = AllocExplosion();
					Math3D.VectorCopy(pos, ex.ent.origin);
					ex.type = ex_poly;
					ex.ent.flags = Defines.RF_FULLBRIGHT;
					ex.start = Globals.cl.frame.servertime - 100;
					ex.light = 350;
					ex.lightcolor[0] = 1.0f;
					ex.lightcolor[1] = 0.5f;
					ex.lightcolor[2] = 0.5f;
					ex.ent.angles[1] = Lib.rand() % 360;
					ex.ent.model = cl_mod_explo4;
					if ((float) Globals.rnd.NextDouble() < 0.5)
						ex.baseframe = 15;
					ex.frames = 15;
					CL_fx.ExplosionParticles(pos);
					S.StartSound(pos, 0, 0, cl_sfx_rockexp, 1, Defines.ATTN_NORM, 0);
					break;
				
				
				case Defines.TE_EXPLOSION1: 
				case Defines.TE_EXPLOSION1_BIG: 
				// PMM
				case Defines.TE_ROCKET_EXPLOSION: 
				case Defines.TE_ROCKET_EXPLOSION_WATER: 
				case Defines.TE_EXPLOSION1_NP:  // PMM
					MSG.ReadPos(Globals.net_message, pos);
					
					ex = AllocExplosion();
					Math3D.VectorCopy(pos, ex.ent.origin);
					ex.type = ex_poly;
					ex.ent.flags = Defines.RF_FULLBRIGHT;
					ex.start = Globals.cl.frame.servertime - 100;
					ex.light = 350;
					ex.lightcolor[0] = 1.0f;
					ex.lightcolor[1] = 0.5f;
					ex.lightcolor[2] = 0.5f;
					ex.ent.angles[1] = Lib.rand() % 360;
					if (type != Defines.TE_EXPLOSION1_BIG)
					// PMM
						ex.ent.model = cl_mod_explo4;
					// PMM
					else
						ex.ent.model = cl_mod_explo4_big;
					if ((float) Globals.rnd.NextDouble() < 0.5)
						ex.baseframe = 15;
					ex.frames = 15;
					if ((type != Defines.TE_EXPLOSION1_BIG) && (type != Defines.TE_EXPLOSION1_NP))
					// PMM
						CL_fx.ExplosionParticles(pos); // PMM
					if (type == Defines.TE_ROCKET_EXPLOSION_WATER)
						S.StartSound(pos, 0, 0, cl_sfx_watrexp, 1, Defines.ATTN_NORM, 0);
					else
						S.StartSound(pos, 0, 0, cl_sfx_rockexp, 1, Defines.ATTN_NORM, 0);
					break;
				
				
				case Defines.TE_BFG_EXPLOSION: 
					MSG.ReadPos(Globals.net_message, pos);
					ex = AllocExplosion();
					Math3D.VectorCopy(pos, ex.ent.origin);
					ex.type = ex_poly;
					ex.ent.flags = Defines.RF_FULLBRIGHT;
					ex.start = Globals.cl.frame.servertime - 100;
					ex.light = 350;
					ex.lightcolor[0] = 0.0f;
					ex.lightcolor[1] = 1.0f;
					ex.lightcolor[2] = 0.0f;
					ex.ent.model = cl_mod_bfg_explo;
					ex.ent.flags |= Defines.RF_TRANSLUCENT;
					ex.ent.alpha = 0.30f;
					ex.frames = 4;
					break;
				
				
				case Defines.TE_BFG_BIGEXPLOSION: 
					MSG.ReadPos(Globals.net_message, pos);
					CL_fx.BFGExplosionParticles(pos);
					break;
				
				
				case Defines.TE_BFG_LASER: 
					ParseLaser(unchecked((int) 0xd0d1d2d3));
					break;
				
				
				case Defines.TE_BUBBLETRAIL: 
					MSG.ReadPos(Globals.net_message, pos);
					MSG.ReadPos(Globals.net_message, pos2);
					CL_fx.BubbleTrail(pos, pos2);
					break;
				
				
				case Defines.TE_PARASITE_ATTACK: 
				case Defines.TE_MEDIC_CABLE_ATTACK: 
					ent = ParseBeam(cl_mod_parasite_segment);
					break;
				
				
				case Defines.TE_BOSSTPORT:  // boss teleporting to station
					MSG.ReadPos(Globals.net_message, pos);
					CL_fx.BigTeleportParticles(pos);
					S.StartSound(pos, 0, 0, S.RegisterSound("misc/bigtele.wav"), 1, Defines.ATTN_NONE, 0);
					break;
				
				
				case Defines.TE_GRAPPLE_CABLE: 
					ent = ParseBeam2(cl_mod_grapple_cable);
					break;
					
					// RAFAEL
				
				case Defines.TE_WELDING_SPARKS: 
					cnt = MSG.ReadByte(Globals.net_message);
					MSG.ReadPos(Globals.net_message, pos);
					MSG.ReadDir(Globals.net_message, dir);
					color = MSG.ReadByte(Globals.net_message);
					CL_fx.ParticleEffect2(pos, dir, color, cnt);
					
					ex = AllocExplosion();
					Math3D.VectorCopy(pos, ex.ent.origin);
					ex.type = ex_flash;
					// note to self
					// we need a better no draw flag
					ex.ent.flags = Defines.RF_BEAM;
					ex.start = Globals.cl.frame.servertime - 0.1f;
					ex.light = 100 + (Lib.rand() % 75);
					ex.lightcolor[0] = 1.0f;
					ex.lightcolor[1] = 1.0f;
					ex.lightcolor[2] = 0.3f;
					ex.ent.model = cl_mod_flash;
					ex.frames = 2;
					break;
				
				
				case Defines.TE_GREENBLOOD: 
					MSG.ReadPos(Globals.net_message, pos);
					MSG.ReadDir(Globals.net_message, dir);
					CL_fx.ParticleEffect2(pos, dir, 0xdf, 30);
					break;
					
					// RAFAEL
				
				case Defines.TE_TUNNEL_SPARKS: 
					cnt = MSG.ReadByte(Globals.net_message);
					MSG.ReadPos(Globals.net_message, pos);
					MSG.ReadDir(Globals.net_message, dir);
					color = MSG.ReadByte(Globals.net_message);
					CL_fx.ParticleEffect3(pos, dir, color, cnt);
					break;
					
					//	  =============
					//	  PGM
					// PMM -following code integrated for flechette (different color)
				
				case Defines.TE_BLASTER2: 
				// green blaster hitting wall
				case Defines.TE_FLECHETTE:  // flechette
					MSG.ReadPos(Globals.net_message, pos);
					MSG.ReadDir(Globals.net_message, dir);
					
					// PMM
					if (type == Defines.TE_BLASTER2)
						CL_newfx.BlasterParticles2(pos, dir, 0xd0);
					else
						CL_newfx.BlasterParticles2(pos, dir, 0x6f); // 75
					
					ex = AllocExplosion();
					Math3D.VectorCopy(pos, ex.ent.origin);
					//UPGRADE_WARNING: Data types in Visual C# might be different.  Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'"
					ex.ent.angles[0] = (float) (System.Math.Acos(dir[2]) / System.Math.PI * 180);
					// PMM - fixed to correct for pitch of 0
					if (dir[0] != 0.0f)
					{
						//UPGRADE_WARNING: Data types in Visual C# might be different.  Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'"
						ex.ent.angles[1] = (float) (System.Math.Atan2(dir[1], dir[0]) / System.Math.PI * 180);
					}
					else if (dir[1] > 0)
						ex.ent.angles[1] = 90;
					else if (dir[1] < 0)
						ex.ent.angles[1] = 270;
					else
						ex.ent.angles[1] = 0;
					
					ex.type = ex_misc;
					ex.ent.flags = Defines.RF_FULLBRIGHT | Defines.RF_TRANSLUCENT;
					
					// PMM
					if (type == Defines.TE_BLASTER2)
						ex.ent.skinnum = 1;
					// flechette
					else
						ex.ent.skinnum = 2;
					
					ex.start = Globals.cl.frame.servertime - 100;
					ex.light = 150;
					// PMM
					if (type == Defines.TE_BLASTER2)
						ex.lightcolor[1] = 1;
					// flechette
					else
					{
						ex.lightcolor[0] = 0.19f;
						ex.lightcolor[1] = 0.41f;
						ex.lightcolor[2] = 0.75f;
					}
					ex.ent.model = cl_mod_explode;
					ex.frames = 4;
					S.StartSound(pos, 0, 0, cl_sfx_lashit, 1, Defines.ATTN_NORM, 0);
					break;
				
				
				case Defines.TE_LIGHTNING: 
					ent = ParseLightning(cl_mod_lightning);
					S.StartSound(null, ent, Defines.CHAN_WEAPON, cl_sfx_lightning, 1, Defines.ATTN_NORM, 0);
					break;
				
				
				case Defines.TE_DEBUGTRAIL: 
					MSG.ReadPos(Globals.net_message, pos);
					MSG.ReadPos(Globals.net_message, pos2);
					CL_newfx.DebugTrail(pos, pos2);
					break;
				
				
				case Defines.TE_PLAIN_EXPLOSION: 
					MSG.ReadPos(Globals.net_message, pos);
					
					ex = AllocExplosion();
					Math3D.VectorCopy(pos, ex.ent.origin);
					ex.type = ex_poly;
					ex.ent.flags = Defines.RF_FULLBRIGHT;
					ex.start = Globals.cl.frame.servertime - 100;
					ex.light = 350;
					ex.lightcolor[0] = 1.0f;
					ex.lightcolor[1] = 0.5f;
					ex.lightcolor[2] = 0.5f;
					ex.ent.angles[1] = Lib.rand() % 360;
					ex.ent.model = cl_mod_explo4;
					if ((float) Globals.rnd.NextDouble() < 0.5)
						ex.baseframe = 15;
					ex.frames = 15;
					if (type == Defines.TE_ROCKET_EXPLOSION_WATER)
						S.StartSound(pos, 0, 0, cl_sfx_watrexp, 1, Defines.ATTN_NORM, 0);
					else
						S.StartSound(pos, 0, 0, cl_sfx_rockexp, 1, Defines.ATTN_NORM, 0);
					break;
				
				
				case Defines.TE_FLASHLIGHT: 
					MSG.ReadPos(Globals.net_message, pos);
					ent = MSG.ReadShort(Globals.net_message);
					CL_newfx.Flashlight(ent, pos);
					break;
				
				
				case Defines.TE_FORCEWALL: 
					MSG.ReadPos(Globals.net_message, pos);
					MSG.ReadPos(Globals.net_message, pos2);
					color = MSG.ReadByte(Globals.net_message);
					CL_newfx.ForceWall(pos, pos2, color);
					break;
				
				
				case Defines.TE_HEATBEAM: 
					ent = ParsePlayerBeam(cl_mod_heatbeam);
					break;
				
				
				case Defines.TE_MONSTER_HEATBEAM: 
					ent = ParsePlayerBeam(cl_mod_monster_heatbeam);
					break;
				
				
				case Defines.TE_HEATBEAM_SPARKS: 
					//			cnt = MSG.ReadByte (net_message);
					cnt = 50;
					MSG.ReadPos(Globals.net_message, pos);
					MSG.ReadDir(Globals.net_message, dir);
					//			r = MSG.ReadByte (net_message);
					//			magnitude = MSG.ReadShort (net_message);
					r = 8;
					magnitude = 60;
					color = r & 0xff;
					CL_newfx.ParticleSteamEffect(pos, dir, color, cnt, magnitude);
					S.StartSound(pos, 0, 0, cl_sfx_lashit, 1, Defines.ATTN_NORM, 0);
					break;
				
				
				case Defines.TE_HEATBEAM_STEAM: 
					//			cnt = MSG.ReadByte (net_message);
					cnt = 20;
					MSG.ReadPos(Globals.net_message, pos);
					MSG.ReadDir(Globals.net_message, dir);
					//			r = MSG.ReadByte (net_message);
					//			magnitude = MSG.ReadShort (net_message);
					//			color = r & 0xff;
					color = 0xe0;
					magnitude = 60;
					CL_newfx.ParticleSteamEffect(pos, dir, color, cnt, magnitude);
					S.StartSound(pos, 0, 0, cl_sfx_lashit, 1, Defines.ATTN_NORM, 0);
					break;
				
				
				case Defines.TE_STEAM: 
					ParseSteam();
					break;
				
				
				case Defines.TE_BUBBLETRAIL2: 
					//			cnt = MSG.ReadByte (net_message);
					cnt = 8;
					MSG.ReadPos(Globals.net_message, pos);
					MSG.ReadPos(Globals.net_message, pos2);
					CL_newfx.BubbleTrail2(pos, pos2, cnt);
					S.StartSound(pos, 0, 0, cl_sfx_lashit, 1, Defines.ATTN_NORM, 0);
					break;
				
				
				case Defines.TE_MOREBLOOD: 
					MSG.ReadPos(Globals.net_message, pos);
					MSG.ReadDir(Globals.net_message, dir);
					CL_fx.ParticleEffect(pos, dir, 0xe8, 250);
					break;
				
				
				case Defines.TE_CHAINFIST_SMOKE: 
					dir[0] = 0;
					dir[1] = 0;
					dir[2] = 1;
					MSG.ReadPos(Globals.net_message, pos);
					CL_newfx.ParticleSmokeEffect(pos, dir, 0, 20, 20);
					break;
				
				
				case Defines.TE_ELECTRIC_SPARKS: 
					MSG.ReadPos(Globals.net_message, pos);
					MSG.ReadDir(Globals.net_message, dir);
					//			CL_ParticleEffect (pos, dir, 109, 40);
					CL_fx.ParticleEffect(pos, dir, 0x75, 40);
					//FIXME : replace or remove this sound
					S.StartSound(pos, 0, 0, cl_sfx_lashit, 1, Defines.ATTN_NORM, 0);
					break;
				
				
				case Defines.TE_TRACKER_EXPLOSION: 
					MSG.ReadPos(Globals.net_message, pos);
					CL_newfx.ColorFlash(pos, 0, 150, - 1, - 1, - 1);
					CL_newfx.ColorExplosionParticles(pos, 0, 1);
					S.StartSound(pos, 0, 0, cl_sfx_disrexp, 1, Defines.ATTN_NORM, 0);
					break;
				
				
				case Defines.TE_TELEPORT_EFFECT: 
				case Defines.TE_DBALL_GOAL: 
					MSG.ReadPos(Globals.net_message, pos);
					CL_fx.TeleportParticles(pos);
					break;
				
				
				case Defines.TE_WIDOWBEAMOUT: 
					ParseWidow();
					break;
				
				
				case Defines.TE_NUKEBLAST: 
					ParseNuke();
					break;
				
				
				case Defines.TE_WIDOWSPLASH: 
					MSG.ReadPos(Globals.net_message, pos);
					CL_newfx.WidowSplash(pos);
					break;
					//	  PGM
					//	  ==============
				
				
				default: 
					Com.Error(Defines.ERR_DROP, "CL_ParseTEnt: bad type");
					break;
				
			}
		}
		
		// stack variable
		// dist, org
		//UPGRADE_NOTE: Final was removed from the declaration of 'ent '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
		private static readonly entity_t ent = new entity_t();
		/*
		* ================= CL_AddBeams =================
		*/
		internal static void  AddBeams()
		{
			int i, j;
			beam_t[] b;
			float d;
			float yaw, pitch;
			float forward;
			float len, steps;
			float model_length;
			
			//	   update beams
			b = cl_beams;
			for (i = 0; i < MAX_BEAMS; i++)
			{
				if (b[i].model == null || b[i].endtime < Globals.cl.time)
					continue;
				
				// if coming from the player, update the start position
				if (b[i].entity == Globals.cl.playernum + 1)
				// entity 0 is the
				// world
				{
					Math3D.VectorCopy(Globals.cl.refdef.vieworg, b[i].start);
					b[i].start[2] -= 22; // adjust for view height
				}
				Math3D.VectorAdd(b[i].start, b[i].offset, org);
				
				// calculate pitch and yaw
				Math3D.VectorSubtract(b[i].end, org, dist);
				
				if (dist[1] == 0 && dist[0] == 0)
				{
					yaw = 0;
					if (dist[2] > 0)
						pitch = 90;
					else
						pitch = 270;
				}
				else
				{
					// PMM - fixed to correct for pitch of 0
					if (dist[0] != 0.0f)
					{
						//UPGRADE_WARNING: Data types in Visual C# might be different.  Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'"
						yaw = (float) (System.Math.Atan2(dist[1], dist[0]) * 180 / System.Math.PI);
					}
					else if (dist[1] > 0)
						yaw = 90;
					else
						yaw = 270;
					if (yaw < 0)
						yaw += 360;
					
					//UPGRADE_WARNING: Data types in Visual C# might be different.  Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'"
					forward = (float) System.Math.Sqrt(dist[0] * dist[0] + dist[1] * dist[1]);
					//UPGRADE_WARNING: Data types in Visual C# might be different.  Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'"
					pitch = (float) (System.Math.Atan2(dist[2], forward) * (- 180.0) / System.Math.PI);
					if (pitch < 0)
						pitch = (float) (pitch + 360.0);
				}
				
				// add new entities for the beams
				d = Math3D.VectorNormalize(dist);
				
				//memset (&ent, 0, sizeof(ent));
				ent.clear();
				if (b[i].model == cl_mod_lightning)
				{
					model_length = 35.0f;
					d = (float) (d - 20.0); // correction so it doesn't end in middle of tesla
				}
				else
				{
					model_length = 30.0f;
				}
				//UPGRADE_WARNING: Data types in Visual C# might be different.  Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'"
				steps = (float) System.Math.Ceiling(d / model_length);
				len = (d - model_length) / (steps - 1);
				
				// PMM - special case for lightning model .. if the real length is
				// shorter than the model,
				// flip it around & draw it from the end to the start. This prevents
				// the model from going
				// through the tesla mine (instead it goes through the target)
				if ((b[i].model == cl_mod_lightning) && (d <= model_length))
				{
					//				Com_Printf ("special case\n");
					Math3D.VectorCopy(b[i].end, ent.origin);
					// offset to push beam outside of tesla model (negative because
					// dist is from end to start
					// for this beam)
					//				for (j=0 ; j<3 ; j++)
					//					ent.origin[j] -= dist[j]*10.0;
					ent.model = b[i].model;
					ent.flags = Defines.RF_FULLBRIGHT;
					ent.angles[0] = pitch;
					ent.angles[1] = yaw;
					ent.angles[2] = Lib.rand() % 360;
					V.AddEntity(ent);
					return ;
				}
				while (d > 0)
				{
					Math3D.VectorCopy(org, ent.origin);
					ent.model = b[i].model;
					if (b[i].model == cl_mod_lightning)
					{
						ent.flags = Defines.RF_FULLBRIGHT;
						ent.angles[0] = - pitch;
						ent.angles[1] = yaw + 180.0f;
						ent.angles[2] = Lib.rand() % 360;
					}
					else
					{
						ent.angles[0] = pitch;
						ent.angles[1] = yaw;
						ent.angles[2] = Lib.rand() % 360;
					}
					
					//				Com_Printf("B: %d . %d\n", b[i].entity, b[i].dest_entity);
					V.AddEntity(ent);
					
					for (j = 0; j < 3; j++)
						org[j] += dist[j] * len;
					d -= model_length;
				}
			}
		}
		
		//extern cvar_t *hand;
		
		// stack variable
		//UPGRADE_NOTE: Final was removed from the declaration of 'dist '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
		private static readonly float[] dist = new float[3];
		//UPGRADE_NOTE: Final was removed from the declaration of 'org '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
		private static readonly float[] org = new float[3];
		//UPGRADE_NOTE: Final was removed from the declaration of 'f '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
		private static readonly float[] f = new float[3];
		//UPGRADE_NOTE: Final was removed from the declaration of 'u '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
		private static readonly float[] u = new float[3];
		//UPGRADE_NOTE: Final was removed from the declaration of 'r '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
		private static readonly float[] r = new float[3];
		/*
		* ================= ROGUE - draw player locked beams CL_AddPlayerBeams
		* =================
		*/
		internal static void  AddPlayerBeams()
		{
			float d;
			//entity_t ent = new entity_t();
			float yaw, pitch;
			float forward;
			float len, steps;
			int framenum = 0;
			float model_length;
			
			float hand_multiplier;
			frame_t oldframe;
			player_state_t ps, ops;
			
			//	  PMM
			if (Globals.hand != null)
			{
				if (Globals.hand.value_Renamed == 2)
					hand_multiplier = 0;
				else if (Globals.hand.value_Renamed == 1)
					hand_multiplier = - 1;
				else
					hand_multiplier = 1;
			}
			else
			{
				hand_multiplier = 1;
			}
			//	  PMM
			
			//	   update beams
			beam_t[] b = cl_playerbeams;
			for (int i = 0; i < MAX_BEAMS; i++)
			{
				
				if (b[i].model == null || b[i].endtime < Globals.cl.time)
					continue;
				
				if (cl_mod_heatbeam != null && (b[i].model == cl_mod_heatbeam))
				{
					
					// if coming from the player, update the start position
					if (b[i].entity == Globals.cl.playernum + 1)
					// entity 0 is the
					// world
					{
						// set up gun position
						// code straight out of CL_AddViewWeapon
						ps = Globals.cl.frame.playerstate;
						int j = (Globals.cl.frame.serverframe - 1) & Defines.UPDATE_MASK;
						oldframe = Globals.cl.frames[j];
						
						if (oldframe.serverframe != Globals.cl.frame.serverframe - 1 || !oldframe.valid)
							oldframe = Globals.cl.frame; // previous frame was
						// dropped or involid
						
						ops = oldframe.playerstate;
						for (j = 0; j < 3; j++)
						{
							b[i].start[j] = Globals.cl.refdef.vieworg[j] + ops.gunoffset[j] + Globals.cl.lerpfrac * (ps.gunoffset[j] - ops.gunoffset[j]);
						}
						Math3D.VectorMA(b[i].start, (hand_multiplier * b[i].offset[0]), Globals.cl.v_right, org);
						Math3D.VectorMA(org, b[i].offset[1], Globals.cl.v_forward, org);
						Math3D.VectorMA(org, b[i].offset[2], Globals.cl.v_up, org);
						if ((Globals.hand != null) && (Globals.hand.value_Renamed == 2))
						{
							Math3D.VectorMA(org, - 1, Globals.cl.v_up, org);
						}
						// FIXME - take these out when final
						Math3D.VectorCopy(Globals.cl.v_right, r);
						Math3D.VectorCopy(Globals.cl.v_forward, f);
						Math3D.VectorCopy(Globals.cl.v_up, u);
					}
					else
						Math3D.VectorCopy(b[i].start, org);
				}
				else
				{
					// if coming from the player, update the start position
					if (b[i].entity == Globals.cl.playernum + 1)
					// entity 0 is the
					// world
					{
						Math3D.VectorCopy(Globals.cl.refdef.vieworg, b[i].start);
						b[i].start[2] -= 22; // adjust for view height
					}
					Math3D.VectorAdd(b[i].start, b[i].offset, org);
				}
				
				// calculate pitch and yaw
				Math3D.VectorSubtract(b[i].end, org, dist);
				
				//	  PMM
				if (cl_mod_heatbeam != null && (b[i].model == cl_mod_heatbeam) && (b[i].entity == Globals.cl.playernum + 1))
				{
					
					len = Math3D.VectorLength(dist);
					Math3D.VectorScale(f, len, dist);
					Math3D.VectorMA(dist, (hand_multiplier * b[i].offset[0]), r, dist);
					Math3D.VectorMA(dist, b[i].offset[1], f, dist);
					Math3D.VectorMA(dist, b[i].offset[2], u, dist);
					if ((Globals.hand != null) && (Globals.hand.value_Renamed == 2))
					{
						Math3D.VectorMA(org, - 1, Globals.cl.v_up, org);
					}
				}
				//	  PMM
				
				if (dist[1] == 0 && dist[0] == 0)
				{
					yaw = 0;
					if (dist[2] > 0)
						pitch = 90;
					else
						pitch = 270;
				}
				else
				{
					// PMM - fixed to correct for pitch of 0
					if (dist[0] != 0.0f)
					{
						//UPGRADE_WARNING: Data types in Visual C# might be different.  Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'"
						yaw = (float) (System.Math.Atan2(dist[1], dist[0]) * 180 / System.Math.PI);
					}
					else if (dist[1] > 0)
						yaw = 90;
					else
						yaw = 270;
					if (yaw < 0)
						yaw += 360;
					
					//UPGRADE_WARNING: Data types in Visual C# might be different.  Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'"
					forward = (float) System.Math.Sqrt(dist[0] * dist[0] + dist[1] * dist[1]);
					//UPGRADE_WARNING: Data types in Visual C# might be different.  Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'"
					pitch = (float) (System.Math.Atan2(dist[2], forward) * (- 180.0) / System.Math.PI);
					if (pitch < 0)
						pitch = (float) (pitch + 360.0);
				}
				
				if (cl_mod_heatbeam != null && (b[i].model == cl_mod_heatbeam))
				{
					if (b[i].entity != Globals.cl.playernum + 1)
					{
						framenum = 2;
						//					Com_Printf ("Third person\n");
						ent.angles[0] = - pitch;
						ent.angles[1] = yaw + 180.0f;
						ent.angles[2] = 0;
						//					Com_Printf ("%f %f - %f %f %f\n", -pitch, yaw+180.0,
						// b[i].offset[0], b[i].offset[1], b[i].offset[2]);
						Math3D.AngleVectors(ent.angles, f, r, u);
						
						// if it's a non-origin offset, it's a player, so use the
						// hardcoded player offset
						if (!Math3D.VectorEquals(b[i].offset, Globals.vec3_origin))
						{
							Math3D.VectorMA(org, - (b[i].offset[0]) + 1, r, org);
							Math3D.VectorMA(org, - (b[i].offset[1]), f, org);
							Math3D.VectorMA(org, - (b[i].offset[2]) - 10, u, org);
						}
						else
						{
							// if it's a monster, do the particle effect
							CL_newfx.MonsterPlasma_Shell(b[i].start);
						}
					}
					else
					{
						framenum = 1;
					}
				}
				
				// if it's the heatbeam, draw the particle effect
				if ((cl_mod_heatbeam != null && (b[i].model == cl_mod_heatbeam) && (b[i].entity == Globals.cl.playernum + 1)))
				{
					CL_newfx.Heatbeam(org, dist);
				}
				
				// add new entities for the beams
				d = Math3D.VectorNormalize(dist);
				
				//memset (&ent, 0, sizeof(ent));
				ent.clear();
				
				if (b[i].model == cl_mod_heatbeam)
				{
					model_length = 32.0f;
				}
				else if (b[i].model == cl_mod_lightning)
				{
					model_length = 35.0f;
					d = (float) (d - 20.0); // correction so it doesn't end in middle of tesla
				}
				else
				{
					model_length = 30.0f;
				}
				//UPGRADE_WARNING: Data types in Visual C# might be different.  Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'"
				steps = (float) System.Math.Ceiling(d / model_length);
				len = (d - model_length) / (steps - 1);
				
				// PMM - special case for lightning model .. if the real length is
				// shorter than the model,
				// flip it around & draw it from the end to the start. This prevents
				// the model from going
				// through the tesla mine (instead it goes through the target)
				if ((b[i].model == cl_mod_lightning) && (d <= model_length))
				{
					//				Com_Printf ("special case\n");
					Math3D.VectorCopy(b[i].end, ent.origin);
					// offset to push beam outside of tesla model (negative because
					// dist is from end to start
					// for this beam)
					//				for (j=0 ; j<3 ; j++)
					//					ent.origin[j] -= dist[j]*10.0;
					ent.model = b[i].model;
					ent.flags = Defines.RF_FULLBRIGHT;
					ent.angles[0] = pitch;
					ent.angles[1] = yaw;
					ent.angles[2] = Lib.rand() % 360;
					V.AddEntity(ent);
					return ;
				}
				while (d > 0)
				{
					Math3D.VectorCopy(org, ent.origin);
					ent.model = b[i].model;
					if (cl_mod_heatbeam != null && (b[i].model == cl_mod_heatbeam))
					{
						//					ent.flags = RF_FULLBRIGHT|RF_TRANSLUCENT;
						//					ent.alpha = 0.3;
						ent.flags = Defines.RF_FULLBRIGHT;
						ent.angles[0] = - pitch;
						ent.angles[1] = yaw + 180.0f;
						ent.angles[2] = (Globals.cl.time) % 360;
						//					ent.angles[2] = rand()%360;
						ent.frame = framenum;
					}
					else if (b[i].model == cl_mod_lightning)
					{
						ent.flags = Defines.RF_FULLBRIGHT;
						ent.angles[0] = - pitch;
						ent.angles[1] = yaw + 180.0f;
						ent.angles[2] = Lib.rand() % 360;
					}
					else
					{
						ent.angles[0] = pitch;
						ent.angles[1] = yaw;
						ent.angles[2] = Lib.rand() % 360;
					}
					
					//				Com_Printf("B: %d . %d\n", b[i].entity, b[i].dest_entity);
					V.AddEntity(ent);
					
					for (int j = 0; j < 3; j++)
						org[j] += dist[j] * len;
					d -= model_length;
				}
			}
		}
		
		/*
		* ================= CL_AddExplosions =================
		*/
		internal static void  AddExplosions()
		{
			entity_t ent;
			int i;
			explosion_t[] ex;
			float frac;
			int f;
			
			//memset (&ent, 0, sizeof(ent)); Pointer!
			ent = null;
			ex = cl_explosions;
			for (i = 0; i < MAX_EXPLOSIONS; i++)
			{
				if (ex[i].type == ex_free)
					continue;
				frac = (Globals.cl.time - ex[i].start) / 100.0f;
				//UPGRADE_WARNING: Data types in Visual C# might be different.  Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'"
				f = (int) System.Math.Floor(frac);
				
				ent = ex[i].ent;
				
				switch (ex[i].type)
				{
					
					case ex_mflash: 
						if (f >= ex[i].frames - 1)
							ex[i].type = ex_free;
						break;
					
					case ex_misc: 
						if (f >= ex[i].frames - 1)
						{
							ex[i].type = ex_free;
							break;
						}
						ent.alpha = 1.0f - frac / (ex[i].frames - 1);
						break;
					
					case ex_flash: 
						if (f >= 1)
						{
							ex[i].type = ex_free;
							break;
						}
						ent.alpha = 1.0f;
						break;
					
					case ex_poly: 
						if (f >= ex[i].frames - 1)
						{
							ex[i].type = ex_free;
							break;
						}
						
						//UPGRADE_WARNING: Data types in Visual C# might be different.  Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'"
						ent.alpha = (16.0f - (float) f) / 16.0f;
						
						if (f < 10)
						{
							ent.skinnum = (f >> 1);
							if (ent.skinnum < 0)
								ent.skinnum = 0;
						}
						else
						{
							ent.flags |= Defines.RF_TRANSLUCENT;
							if (f < 13)
								ent.skinnum = 5;
							else
								ent.skinnum = 6;
						}
						break;
					
					case ex_poly2: 
						if (f >= ex[i].frames - 1)
						{
							ex[i].type = ex_free;
							break;
						}
						
						//UPGRADE_WARNING: Data types in Visual C# might be different.  Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'"
						ent.alpha = (5.0f - (float) f) / 5.0f;
						ent.skinnum = 0;
						ent.flags |= Defines.RF_TRANSLUCENT;
						break;
					}
				
				if (ex[i].type == ex_free)
					continue;
				if (ex[i].light != 0.0f)
				{
					V.AddLight(ent.origin, ex[i].light * ent.alpha, ex[i].lightcolor[0], ex[i].lightcolor[1], ex[i].lightcolor[2]);
				}
				
				Math3D.VectorCopy(ent.origin, ent.oldorigin);
				
				if (f < 0)
					f = 0;
				ent.frame = ex[i].baseframe + f + 1;
				ent.oldframe = ex[i].baseframe + f;
				ent.backlerp = 1.0f - Globals.cl.lerpfrac;
				
				V.AddEntity(ent);
			}
		}
		
		/*
		* ================= CL_AddLasers =================
		*/
		internal static void  AddLasers()
		{
			laser_t[] l;
			int i;
			
			l = cl_lasers;
			for (i = 0; i < MAX_LASERS; i++)
			{
				if (l[i].endtime >= Globals.cl.time)
					V.AddEntity(l[i].ent);
			}
		}
		
		/* PMM - CL_Sustains */
		internal static void  ProcessSustain()
		{
			cl_sustain_t[] s;
			int i;
			
			s = cl_sustains;
			for (i = 0; i < MAX_SUSTAINS; i++)
			{
				if (s[i].id != 0)
					if ((s[i].endtime >= Globals.cl.time) && (Globals.cl.time >= s[i].nextthink))
					{
						s[i].think.think(s[i]);
					}
					else if (s[i].endtime < Globals.cl.time)
						s[i].id = 0;
			}
		}
		
		/*
		* ================= CL_AddTEnts =================
		*/
		internal static void  AddTEnts()
		{
			AddBeams();
			// PMM - draw plasma beams
			AddPlayerBeams();
			AddExplosions();
			AddLasers();
			// PMM - set up sustain
			ProcessSustain();
		}
		static CL_tent()
		{
			{
				for (int i = 0; i < cl_explosions.Length; i++)
					cl_explosions[i] = new explosion_t();
			}
			{
				for (int i = 0; i < cl_beams.Length; i++)
					cl_beams[i] = new beam_t();
				for (int i = 0; i < cl_playerbeams.Length; i++)
					cl_playerbeams[i] = new beam_t();
			}
			{
				for (int i = 0; i < cl_lasers.Length; i++)
					cl_lasers[i] = new laser_t();
			}
			{
				for (int i = 0; i < cl_sustains.Length; i++)
					cl_sustains[i] = new cl_sustain_t();
			}
		}
	}
}